package com.songlanyun.modules.account.controller.admin;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.result.ExcelImportResult;
import cn.hutool.core.util.ObjectUtil;
import com.songlanyun.common.annotation.AuthIgnore;
import com.songlanyun.common.annotation.SysLog;
import com.songlanyun.common.exception.RRException;
import com.songlanyun.common.utils.DateUtils;
import com.songlanyun.common.utils.PageUtils;
import com.songlanyun.common.utils.R;
import com.songlanyun.modules.account.entity.AccountEntity;
import com.songlanyun.modules.account.model.dto.ImportUserDTO;
import com.songlanyun.modules.account.model.dto.ServiceSystemDTO;
import com.songlanyun.modules.account.model.vo.AccountExportVO;
import com.songlanyun.modules.account.model.vo.AccountInfoVO;
import com.songlanyun.modules.account.model.vo.AccountVO;
import com.songlanyun.modules.account.model.vo.MemberStatistics;
import com.songlanyun.modules.account.service.AccountService;
import com.songlanyun.modules.account.service.impl.ImportUserVerifyHandler;
import com.songlanyun.modules.applyareaagent.service.ApplyAreaAgentService;
import com.songlanyun.modules.exception.MemberException;
import com.songlanyun.modules.exception.ShopException;
import com.songlanyun.modules.shop.entity.ShopEntity;
import com.songlanyun.modules.shop.service.ShopService;
import com.songlanyun.modules.user.controller.AbstractController;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.activation.MimetypesFileTypeMap;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.StringJoiner;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;
import java.util.stream.Stream;


/**
 * 会员帐号表（会员的基本信息与关系）
 *
 * @author Mark
 * @email sunlightcs@gmail.com
 * @date 2020-11-02 15:51:10
 */
@RestController
@RequestMapping("admin/account")
public class AccountAdminController extends AbstractController {
    @Autowired
    private AccountService yxtAccountService;
    @Autowired
    private ShopService shopService;
    @Autowired
    private ApplyAreaAgentService applyAreaAgentService;

    @Autowired
    private ThreadPoolExecutor threadPoolExecutor;

    /**
     * 导入数据会员数据验证
     */
    @Resource
    private ImportUserVerifyHandler importUserVerifyHandler;

    private final static Integer MAX_NUMBER = 1000;


    /**
     * 自定义的线程池
     */
    @Autowired
    private ThreadPoolExecutor executor;

    /**
     * 平台查询所有会员列表
     */
    @GetMapping("/list")
//    @RequiresPermissions("account:yxtaccount:list")
    public R list(@RequestParam Map<String, Object> params) {
        setShopIdByPlat(params);
        PageUtils page = yxtAccountService.queryPage(params);

        return R.ok().put("page", page);
    }

    /**
     * 手动激活会员
     */
    @PostMapping("/activation")
    public R activation(@RequestParam Map<String, Object> params) {
        Long userId = Long.valueOf(params.get("id").toString());
        Boolean result = yxtAccountService.activationUser(userId);
        return R.ok().put("result", result);
    }

    /**
     * 商家查询商家下面的会员列表
     */
    @GetMapping("/shopMemberlist")
//    @RequiresPermissions("account:yxtaccount:list")
    public R shopMemberlist(@RequestParam Map<String, Object> params) {
        Long shopId = getShopId();
        if (shopId == 0) {
            throw new RRException(ShopException.SHOP_OPERATION);
        }
        //该商家下面的会员
        params.put("shopId", shopId);

        //应显示所属会员
        PageUtils page = yxtAccountService.queryShopMemberPage(params);
        //显示在当前店铺已有等级的所有用户
//        PageUtils page = yxtAccountService.queryUserShopRolePage(params);
        return R.ok().put("page", page);
    }

    /**
     * 不分页
     */
    @GetMapping("/select")
//    @RequiresPermissions("account:yxtaccount:list")
    public R select(@RequestParam Map<String, Object> params) {
        List<AccountEntity> list = yxtAccountService.select(params);

        return R.ok().put("list", list);
    }


    /**
     * 会员详情信息
     */
    @GetMapping("/info/{id}")
//    @RequiresPermissions("account:yxtaccount:info")
    public R info(@PathVariable("id") Long id) {
        Long shopId = null;
        if (!isShop()) {
            //平台
            shopId = shopService.selectPlatformShopId(true);
        } else {
            //商家管理员
            shopId = getShopId();
        }
        AccountInfoVO yxtAccount = yxtAccountService.getAllById(id, shopId);

        return R.ok().put("data", yxtAccount);
    }


    /**
     * 会员启用禁用
     */
    @SysLog("会员启用禁用")
    @PostMapping("/updateStatus")
//    @RequiresPermissions("account:yxtaccount:info")
    public R updateStatus(@RequestBody AccountEntity accountEntity) {
        if (accountEntity.getId() == null || accountEntity.getLockStatus() == null) {
            throw new RRException(MemberException.INCOMPLETE_PARAMETER);
        }

        yxtAccountService.updateStatus(accountEntity.getId(), accountEntity.getLockStatus());

        return R.ok();
    }
    /**
     * 是否为线下店长修改
     */
    @PostMapping("/updateOflineShopownerStatus")
//    @RequiresPermissions("account:yxtaccount:info")
    public R updateOflineShopownerStatus(@RequestBody AccountEntity accountEntity) {
        if (accountEntity.getId() == null || accountEntity.getOflineShopowner() == null) {
            throw new RRException(MemberException.INCOMPLETE_PARAMETER);
        }

        yxtAccountService.updateOflineShopownerStatus(accountEntity.getId(),accountEntity.getOflineShopowner());

        return R.ok();
    }


    /**
     * 会员导入
     *
     * @param multipartFile
     * @return
     * @throws Exception
     */
    @AuthIgnore
    @PostMapping("/import")
    public R importUser(@RequestParam("file") MultipartFile multipartFile) throws Exception {
        ExcelImportResult<ImportUserDTO> result = null;
        try {
            StringJoiner joiner = new StringJoiner(",");
            ImportParams params = new ImportParams();
            params.setTitleRows(1);
            params.setHeadRows(1);
            // 开启Excel校验
            params.setNeedVerify(true);
            params.setVerifyHandler(importUserVerifyHandler);
            result = ExcelImportUtil.importExcelMore(multipartFile.getInputStream(),
                    ImportUserDTO.class, params);

            System.out.println("是否校验失败: " + result.isVerifyFail());
            for (ImportUserDTO entity : result.getFailList()) {
//                int line = entity.getRowNum() + 1;
//                joiner.add("第" + line + "行的错误是：" + entity.getErrorMsg());
                joiner.add(entity.getUserId().toString());
            }

            if (joiner.length() > 0) {
                logger.error("导入错误数据ID：" + joiner);
                return R.error(joiner.toString());
            }
            //验证后不重复，有效的数据
            List<ImportUserDTO> list = result.getList();//18721
            final Integer limit = countStep(list.size());
            //数据分片
            List<List<ImportUserDTO>> splitList = Stream.iterate(0, n -> n + 1).limit(limit).parallel().map(a -> list.stream()
                    .skip(a * MAX_NUMBER).limit(MAX_NUMBER).parallel().collect(Collectors.toList())).collect(Collectors.toList());

            ShopEntity shop = shopService.selectPlatformShop();
            Long ptShopId = shop.getId();//平台商家id
            Long ptUserId = shop.getUserId();//平台会员id

            splitList.forEach(arr -> {
                //批量导入
                executor.execute(() -> {
                    yxtAccountService.batchImport(arr, ptShopId, ptUserId);
                });
            });


        } finally {
            // 清除threadLocal 防止内存泄漏
            ThreadLocal<List<ImportUserDTO>> threadLocal = importUserVerifyHandler.getThreadLocal();
            if (threadLocal != null) {
                threadLocal.remove();
            }
        }

        return R.ok();
    }

    /**
     * 平台下会员
     * 会员列表导出
     */
    @GetMapping("/export")
    @AuthIgnore
//    @RequiresPermissions("account:yxtaccount:info")
    public void export(@RequestParam Map<String, Object> params, HttpServletResponse response) throws IOException {
        Long adminId = this.getAdminByToken(response);//校验token
        //设置平台商家id
//        Long shopId = shopService.selectPlatformShopId();
//        params.put("shopId", shopId);

        List<AccountExportVO> accountList = yxtAccountService.exportList(params);
        String fileName = "会员列表" + DateUtils.format(new Date(), "yyyy-MM-dd-HHmmss") + "_" + adminId + "." + "xls";
        ExportParams exportParams = new ExportParams("会员列表导出(" + accountList.size() + ")", "会员列表");

        Workbook sheets = ExcelExportUtil.exportExcel(exportParams, AccountExportVO.class, accountList);
        response.setContentType(new MimetypesFileTypeMap().getContentType("application/octet-stream"));// 设置response内容的类型

        response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8"));// 设置头部信息
        sheets.write(response.getOutputStream());
        sheets.close();
    }

    /**
     * 商家下会员
     * 会员列表导出
     */
    @GetMapping("/shop/member/export")
    @AuthIgnore
//    @RequiresPermissions("account:yxtaccount:info")
    public void shopMemberExport(@RequestParam Map<String, Object> params, HttpServletResponse response) throws IOException {
        Long adminId = this.getAdminByToken(response);//校验token

        //查询商家id
        ShopEntity shop = shopService.getShopByAdminId(adminId, false);
        if (shop == null) {
            throw new RRException(ShopException.SHOP_OPERATION);
        }
        params.put("shopId", shop.getId());

        List<AccountVO> accountList = yxtAccountService.shopMemberExportList(params);
        String fileName = "会员列表" + DateUtils.format(new Date(), "yyyy-MM-dd-HHmmss") + "_" + adminId + "." + "xls";
        ExportParams exportParams = new ExportParams("会员列表导出(" + accountList.size() + ")", "会员列表");

        Workbook sheets = ExcelExportUtil.exportExcel(exportParams, AccountVO.class, accountList);
        response.setContentType(new MimetypesFileTypeMap().getContentType("application/octet-stream"));// 设置response内容的类型

        response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8"));// 设置头部信息
        sheets.write(response.getOutputStream());
        sheets.close();
    }

    private void setShopIdByPlat(Map<String, Object> params) {
        Long shopId = null;
        if (isShop()) {
            //商家管理员
            shopId = getShopId();
        }
//        Long shopId = null;
//        if (getShopId() == 0) {
//            shopId = shopService.selectPlatformShopId();
//        }
        params.put("shopId", shopId);
    }

    private static Integer countStep(Integer size) {
        return (size + MAX_NUMBER - 1) / MAX_NUMBER;
    }


    /**
     * 可以修改等级与上下级关系，修改上下级关系是整体层级关系平移过去
     * <p>
     * 改变会员推荐人
     */
    @SysLog("改变会员推荐人")
    @PostMapping("/update-grade")
//    @RequiresPermissions("account:yxtaccount:info")
    public R updateGrade(@RequestBody AccountEntity account) {
        if (account.getId() == null || account.getParentUserId() == null) {
            throw new RRException(MemberException.INCOMPLETE_PARAMETER);
        }
        if (account.getId().equals(account.getParentUserId())) {
            throw new RRException(MemberException.UPDATE_GRADE_NOT_ME);
        }
        String admin = getUser().getUsername();//管理员
        yxtAccountService.updateGrade(account, (remark) -> {
            //保存敏感日志
            this.sensitiveLogCreate("管理员：" + admin + "," + remark.toString());
            return null;
        });
        return R.ok();
    }


    /**
     * 用户总览  -- 会员统计
     */
    @GetMapping("/member-statistics")
//    @RequiresPermissions("account:yxtaccount:info")
    public R memberStatistics() {
        Long shopId = getShopId(false);
        MemberStatistics data = new MemberStatistics();
        CompletableFuture<MemberStatistics> todayMemberNumFuture = CompletableFuture.supplyAsync(() -> {
            //今日新增
            Integer today = yxtAccountService.memberStatistics(shopId, 0);
            data.setToday(today);
            return data;
        }, threadPoolExecutor);

        CompletableFuture<MemberStatistics> yesterdayMemberNumFuture = CompletableFuture.supplyAsync(() -> {
            //昨日新增
            Integer yesterday = yxtAccountService.memberStatistics(shopId, 1);
            data.setYesterday(yesterday);
            return data;
        }, threadPoolExecutor);

        CompletableFuture<MemberStatistics> thisMonthMemberNumFuture = CompletableFuture.supplyAsync(() -> {
            //本月新增
            Integer thisMonth = yxtAccountService.memberStatistics(shopId, 2);
            data.setThisMonth(thisMonth);
            return data;
        }, threadPoolExecutor);

        CompletableFuture<MemberStatistics> sumMemberNumFuture = CompletableFuture.supplyAsync(() -> {
            //会员总数
            Integer sumMember = yxtAccountService.memberStatistics(shopId, null);
            data.setMemberSum(sumMember);
            return data;
        }, threadPoolExecutor);

        try {
            CompletableFuture.allOf(
                    todayMemberNumFuture,
                    yesterdayMemberNumFuture,
                    thisMonthMemberNumFuture,
                    sumMemberNumFuture
            ).get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

        return R.ok().put("data", data);
    }


    /**
     * 获取商家关联用户的邀请码
     *
     * @param
     */
    @GetMapping("/getInvitationCode")
    public R getInvitationCode() {
        //获取会员邀请码
        String invitationCode = null;
        if (ObjectUtil.notEqual(getAreaAgentId(), 0L)) {
            //区县代理
            invitationCode = applyAreaAgentService.getCodeByAreaAgentId(getAreaAgentId());
        } else {
            //商家
            invitationCode = shopService.getCodeByShopId(getShopId());
        }

        return R.ok().put("invitation_code", invitationCode);
    }

}
